﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lenovo.CFI.Common;
using Lenovo.CFI.DAL;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using System.IO;
using NPOI.HPSF;

namespace Lenovo.CFI.BLL
{
    public class ScheduleBl
    {

        public List<ScheduleDetail> GetScheduleWithTimeTable(int topicID)
        {
            List<ScheduleDetail> scheduleDetails = ScheduleDa.GetTopicReviewSchedule(topicID);
            ComputeTimeTable(scheduleDetails);
            return scheduleDetails;
        }

        public List<ScheduleDetail> GetSchedule(int topicID)
        {
            return ScheduleDa.GetTopicReviewSchedule(topicID);
        }


        /// <summary>
        /// 格式化，计算列表中每个时间段的起止时间；必须已经排序
        /// </summary>
        /// <param name="scheduleDetail"></param>
        internal static void ComputeTimeTable(List<ScheduleDetail> scheduleDetails)
        {
            if (scheduleDetails == null || scheduleDetails.Count == 0) return;

            // 第一个必须是Start
            if (scheduleDetails[0].EventType != ScheduleEventType.Start)
                throw new BusinessObjectLogicException("Invalid Event Type");

            DateTime? start = null;
            foreach (ScheduleDetail scheduleDetail in scheduleDetails)
            {
                scheduleDetail.SetTime(start);

                start = scheduleDetail.EndTime;
            }
        }

        internal static string GenerateTimeTable4Email(List<ScheduleDetail> scheduleDetails, Dictionary<int, Idea> reviewIdeas)
        {
            StringBuilder sbItems = new StringBuilder();
            //sbEmail.Append(@"");
            for (int i = 0; i < scheduleDetails.Count; i++)
            {
                ScheduleDetail scheduleDetail = scheduleDetails[i];
                 Idea idea = reviewIdeas[scheduleDetail.IdeaID.Value];

                sbItems.AppendFormat(
                    @"<tr>
                        <td width=""100""><font size=""2"">{0}</font></td>
                        <td width=""100""><font size=""2"">{1}</font></td>
                        <td width=""400""><font size=""2"">{2}</font></td>
                        <td width=""110""><font size=""2"">{3}</font></td>
                      </tr>",
                    i + 1, scheduleDetail.StartTime.ToString("HH:mm"), idea.Title, idea.Owner);
            }

            return string.Format(
                    @"<table width=""960"" border=""1"" cellspacing=""0"" cellpadding=""2"" bordercolor=""#000000"" style=""border-collapse:collapse;font-family:Arial, Helvetica, sans-serif;"">
                        <tr bgcolor=""#CCCCFF"" height=""25"">
                        <td width=""100""><font size=""2""><strong>No.</strong></font></td>
                        <td  width=""100""><font size=""2""><strong>Start Time</strong></font></td>
                        <td width=""400""><font size=""2""><strong>Idea Name</strong></font></td>
                        <td width=""110""><font size=""2""><strong>Author</strong></font></td>
                        </tr>
                        {0}
                      </table>",sbItems);
        }

        public string GenerateTimeTable4Excel(int topicID)
        {
            List<ScheduleDetail> scheduleDetails = new ScheduleBl().GetScheduleWithTimeTable(topicID);
            List<Idea> ideas = IdeaDa.GetIdeaByBelongTopic(topicID);                                    // 此次Topic的Idea
            Dictionary<int, Idea> ideasDic = new Dictionary<int, Idea>();
            foreach (Idea idea in ideas) ideasDic.Add(idea.ID, idea);

            scheduleDetails = scheduleDetails.FindAll(d => d.EventType == ScheduleEventType.Idea);
            scheduleDetails.Sort((x, y) => x.Sort.CompareTo(y.Sort));       // 排序

            Dictionary<int, Idea> reviewIdeasDic = new Dictionary<int, Idea>();     // 实际参与评审的Idea

            // 确定需要Review的Idea
            foreach (ScheduleDetail scheduleDetail in scheduleDetails)
            {

                Idea idea = null;
                if (ideasDic.ContainsKey(scheduleDetail.IdeaID.Value))
                    idea = ideasDic[scheduleDetail.IdeaID.Value];

                // 实际参与评审的Idea
                reviewIdeasDic.Add(scheduleDetail.IdeaID.Value, idea);      // 可能是NULL
            }

            // Idea Owners
            List<int> ideaIDs = new List<int>();
            foreach (var idea in reviewIdeasDic)
            {
                if (idea.Value == null) ideaIDs.Add(idea.Key);
            }
            foreach (Idea idea in IdeaDa.GetByIDs(ideaIDs))
            {
                reviewIdeasDic[idea.ID] = idea;
            }

            return GenerateTimeTable4Excel(scheduleDetails, reviewIdeasDic);
        }

        public string GenerateTimeTable4Excel(List<ScheduleDetail> scheduleDetails, Dictionary<int, Idea> reviewIdeas)
        {
            Workbook workbook = NPOIHelper.CreateWorkbookFromTemplate(TemplatePath.ExcelTemplate() + "\\" + "Schedule.xls");
            Sheet sheet = workbook.GetSheet("Schedule");

            // 填充数据
            if (scheduleDetails!=null)
            {
                for (int i = 0; i < scheduleDetails.Count; i++)
                {
                    ScheduleDetail scheduleDetail = scheduleDetails[i];
                    Idea idea = reviewIdeas[scheduleDetail.IdeaID.Value];
                    Row row = sheet.CreateRow(i + 1);
                    row.CreateCell(0).SetCellValue(i + 1);
                    row.CreateCell(1).SetCellValue(scheduleDetail.StartTime.ToString("HH:mm"));
                    row.CreateCell(2).SetCellValue(idea.Title);
                    row.CreateCell(3).SetCellValue(idea.Owner);
                }
            }
            return NPOIHelper.SaveWorkbookToExcel(Path.GetTempPath(), Path.GetRandomFileName(), workbook);
        }

        /// <summary>
        /// 生成默认的评审时间表
        /// </summary>
        /// <param name="reviewTimeAm">上午开始的时间</param>
        /// <param name="reviewTimePm">下午开始的时间</param>
        /// <returns></returns>
        public void GenerateDefaultSchedule(int topicID, DateTime reviewTimeAm, DateTime reviewTimePm)
        {
            Topic topic = TopicDa.GetTopicByID(topicID);

            // 取出Belong Ideas
            List<Idea> ideas = IdeaDa.GetIdeaByBelongTopic(topicID);
            ideas = ideas.FindAll(i => i.Status == IdeaStatus.ReviewPreparing);
            // 排序
            ideas.Sort(delegate(Idea x, Idea y) 
            {
                int s = x.Type.CompareTo(y.Type);
                if (s == 0) 
                {
                    s = x.Owner.CompareTo(y.Owner);
                    if (s == 0)
                    {
                        x.SubmitTime.CompareTo(y.SubmitTime);
                    }
                }
                return s;
            });
            
            if (ideas.Count == 0) throw new BusinessObjectExistException("there are no ideas to review!");

            int count = ideas.Count;


            // 默认
            int totalWorkingMinuters = 6 * 60;
            int avgMinuters = totalWorkingMinuters / ideas.Count;
            if (avgMinuters > 15) avgMinuters = 15;
            

            List<ScheduleDetail> scheduleDetails = new List<ScheduleDetail>();

            DateTime currentTime = reviewTimeAm;
            int ideaIndex = 0;     

            // 开始
            ScheduleDetail scheduleDetailStart = new ScheduleDetail(topicID, ScheduleEventType.Start);
            scheduleDetailStart.Period = 0;
            scheduleDetailStart.Until = currentTime;
            scheduleDetailStart.Sort = 0;       // Start为0
            scheduleDetails.Add(scheduleDetailStart);

            // 上午
            DateTime h1 = currentTime.Date.AddHours(12);
            while (ideaIndex < ideas.Count && currentTime.AddMinutes(avgMinuters) <= h1)
            {
                ScheduleDetail scheduleDetail = new ScheduleDetail(topicID, ScheduleEventType.Idea);
                scheduleDetail.Idea = ideas[ideaIndex++];
                scheduleDetail.Period = avgMinuters;
                scheduleDetail.Sort = scheduleDetails.Count;
                scheduleDetails.Add(scheduleDetail);

                if (scheduleDetail.Idea.DcAttendMeeting == false)   // 不建议参加的
                    scheduleDetail.Period = 0;
                else
                    currentTime = currentTime.AddMinutes(avgMinuters);
            }

            // 如果还有
            if (ideaIndex < ideas.Count)
            {
                //中午的休息
                currentTime = reviewTimePm;
                ScheduleDetail scheduleDetailBreak = new ScheduleDetail(topicID, ScheduleEventType.Break);
                scheduleDetailBreak.Period = 0;
                scheduleDetailBreak.Until = currentTime;
                scheduleDetailBreak.Sort = scheduleDetails.Count;
                scheduleDetails.Add(scheduleDetailBreak);

                // 下午1
                DateTime h2 = currentTime.AddHours(2);
                while (ideaIndex < ideas.Count && currentTime.AddMinutes(avgMinuters) <= h2)
                {
                    ScheduleDetail scheduleDetail = new ScheduleDetail(topicID, ScheduleEventType.Idea);
                    scheduleDetail.Idea = ideas[ideaIndex++];
                    scheduleDetail.Period = avgMinuters;
                    scheduleDetail.Sort = scheduleDetails.Count;
                    scheduleDetails.Add(scheduleDetail);

                    if (scheduleDetail.Idea.DcAttendMeeting == false)   // 不建议参加的
                        scheduleDetail.Period = 0;
                    else
                        currentTime = currentTime.AddMinutes(avgMinuters);
                }
            }

            // 如果还有
            if (ideaIndex < ideas.Count)
            {
                //下午的休息
                currentTime = reviewTimePm;
                ScheduleDetail scheduleDetailBreak = new ScheduleDetail(topicID, ScheduleEventType.Break);
                scheduleDetailBreak.Period = 15;
                scheduleDetailBreak.Sort = scheduleDetails.Count;
                scheduleDetails.Add(scheduleDetailBreak);

                // 下午2
                while (ideaIndex < ideas.Count)
                {
                    ScheduleDetail scheduleDetail = new ScheduleDetail(topicID, ScheduleEventType.Idea);
                    scheduleDetail.Idea = ideas[ideaIndex++];
                    scheduleDetail.Period = avgMinuters;
                    scheduleDetail.Sort = scheduleDetails.Count;
                    scheduleDetails.Add(scheduleDetail);

                    if (scheduleDetail.Idea.DcAttendMeeting == false)   // 不建议参加的
                        scheduleDetail.Period = 0;
                    else
                        currentTime = currentTime.AddMinutes(avgMinuters);
                }
            }

            // 更新Review Date
            topic.ReviewTime = reviewTimeAm.Date;

            // 存储
            using (TranscationHelper trans = TranscationHelper.GetInstance())
            {
                trans.BeginTrans();
                try
                {
                    TopicDa.UpdateTopic(topic, trans);

                    ScheduleDa.DeleteScheduleByTopicID(topicID, trans);

                    foreach (ScheduleDetail scheduleDetail in scheduleDetails)
                    {
                        ScheduleDa.InsertSchedule(scheduleDetail, trans);
                    }

                    trans.CommitTrans();
                }
                catch
                {
                    trans.RollTrans();
                    throw;
                }
            }
        }


        public void AddIdea(int topicID, int ideaID, int period, int sort)
        {
            Topic topic = TopicDa.GetTopicByID(topicID);
            if (topic == null) throw new BusinessObjectLogicException("The specified topic does not exist!");

            if (topic.Status != TopicStatus.Schedule) throw new BusinessObjectLogicException("The specified topic has been changed!");


            Idea idea = IdeaDa.GetByID(ideaID);
            if (idea.TopicID != topicID) throw new BusinessObjectLogicException("Invalid idea!");

            // 不应当同时被多个Topic Review，如何避免

            ScheduleDetail schedule = new ScheduleDetail(topicID, ScheduleEventType.Idea);
            schedule.Idea = idea;
            schedule.Period = period;
            schedule.Sort = sort;

            ScheduleDa.InsertSchedule(schedule);
        }

        public void ReviewIdea(int topicID, int ideaID, int period, int sort)
        {
            Topic topic = TopicDa.GetTopicByID(topicID);
            if (topic == null) throw new BusinessObjectLogicException("The specified topic does not exist!");

            if (topic.Status != TopicStatus.Schedule) throw new BusinessObjectLogicException("The specified topic has been changed!");


            Idea idea = IdeaDa.GetByID(ideaID);
            if (idea.Status != IdeaStatus.Closed) throw new BusinessObjectLogicException("The specified idea has been reviewed!");

            // 不应当同时被多个Topic Review，如何避免

            ScheduleDetail schedule = new ScheduleDetail(topicID, ScheduleEventType.Idea);
            schedule.Idea = idea;
            schedule.Period = period;
            schedule.Sort = sort;

            ScheduleDa.InsertSchedule(schedule);
        }

        public void UpdateSchedule(int id, int period, DateTime? until, int sort)
        {
            ScheduleDetail schedule = new ScheduleDetail(id);
            schedule.Period = period;
            schedule.Until = until;
            schedule.Sort = sort;

            ScheduleDa.UpdateSchedule(schedule);
        }


        /// <summary>
        /// 批量更新时间表
        /// </summary>
        /// <param name="scheduleDetails"></param>
        public void UpdateSchedules(int topicID, List<ScheduleDetail> scheduleDetails)
        {
            Dictionary<int, ScheduleDetail> detailsDic = new Dictionary<int, ScheduleDetail>();
            foreach (ScheduleDetail detail in scheduleDetails) detailsDic.Add(detail.ID, detail);

            List<ScheduleDetail> exists = ScheduleDa.GetTopicReviewSchedule(topicID);
            foreach (ScheduleDetail exist in exists)
            {
                if (detailsDic.ContainsKey(exist.ID))
                {
                    ScheduleDetail detail = detailsDic[exist.ID];

                    exist.Sort = detail.Sort;

                    if (exist.EventType == ScheduleEventType.Idea)
                        exist.Period = detail.Period;
                }
            }


            using (TranscationHelper trans = TranscationHelper.GetInstance())
            {
                trans.BeginTrans();
                try
                {
                    foreach (ScheduleDetail exist in exists)
                    {
                        ScheduleDa.UpdateSchedule(exist, trans);
                    }

                    trans.CommitTrans();
                }
                catch
                {
                    trans.RollTrans();
                    throw;
                }
            }
        }

        /// <summary>
        /// 往现有的审批时间表插入一个休息
        /// </summary>
        /// <param name="sort"></param>
        /// <param name="scheduleDetail"></param>
        public void InsertBreak(int topicID, int period, DateTime? until, int sort)
        {
            ScheduleDetail schedule = new ScheduleDetail();
            schedule.TopicID = topicID;
            schedule.EventType = ScheduleEventType.Break;
            schedule.Period = period;
            schedule.Until = until;
            schedule.Sort = sort;

            ScheduleDa.InsertSchedule(schedule);
        }

        public void Remove(int id)
        {
            ScheduleDa.DeleteSchedule(id);
        }
    }
}
